//
// DotNetNuke - http://www.dotnetnuke.com
// Copyright (c) 2002-2010
// by Perpetual Motion Interactive Systems Inc. ( http://www.perpetualmotion.ca )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and 
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions 
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
// DEALINGS IN THE SOFTWARE.
//

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization;
using DotNetNuke.Common.Utilities;
using System.Linq;
using DotNetNuke.Entities.Portals;
using DotNetNuke.Services.Localization;

namespace DotNetNuke.Entities.Tabs
{
    [Serializable()]
    public class TabCollection : Dictionary<int, TabInfo>
    {
        private List<TabInfo> list;
        private Dictionary<int, List<TabInfo>> children;
        //This is used to provide a culture based set of tabs
        private Dictionary<String, List<TabInfo>> localizedTabs;

        public TabCollection()
        {
            list = new List<TabInfo>();
            children = new Dictionary<int, List<TabInfo>>();
            localizedTabs = new Dictionary<string, List<TabInfo>>();
        }
        public TabCollection(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }
        public TabCollection(IEnumerable<TabInfo> tabs)
            : this()
        {
            AddRange(tabs);
        }
        private int AddToChildren(TabInfo tab)
        {
            List<TabInfo> childList = null;
            if (!children.TryGetValue(tab.ParentId, out childList))
            {
                childList = new List<TabInfo>();
                children.Add(tab.ParentId, childList);
            }
            childList.Add(tab);
            return childList.Count;
        }

        private void AddToLocalizedTabCollection(TabInfo tab, string cultureCode)
        {
            List<TabInfo> localizedTabCollection = null;

            if (!localizedTabs.TryGetValue(cultureCode.ToLowerInvariant(), out localizedTabCollection))
            {
                localizedTabCollection = new List<TabInfo>();
                localizedTabs.Add(cultureCode.ToLowerInvariant(), localizedTabCollection);
            }

            //Add tab to end of localized tabs
            localizedTabCollection.Add(tab);
        }

        private void AddToLocalizedTabs(TabInfo tab)
        {
            if (string.IsNullOrEmpty(tab.CultureCode))
            {
                //Add to all cultures
                foreach (Locale locale in LocaleController.Instance.GetLocales(tab.PortalID).Values)
                {
                    AddToLocalizedTabCollection(tab, locale.Code);
                }
            }
            else
            {
                AddToLocalizedTabCollection(tab, tab.CultureCode);
            }
        }

        private bool IsLocalizationEnabled()
        {
            PortalSettings _portalSettings = PortalController.GetCurrentPortalSettings();
            if (_portalSettings != null)
            {
                return PortalController.GetPortalSettingAsBoolean("ContentLocalizationEnabled", _portalSettings.PortalId, false);
            }
            else
            {
                return Null.NullBoolean;
            }
        }

        private bool IsLocalizationEnabled(int PortalId)
        {
            return PortalController.GetPortalSettingAsBoolean("ContentLocalizationEnabled", PortalId, false);
        }

        private List<TabInfo> GetDescendants(int tabId, int tabLevel)
        {
            List<TabInfo> descendantTabs = new List<TabInfo>();
            for (int index = 0; index <= list.Count - 1; index++)
            {
                TabInfo parentTab = list[index];
                if (parentTab.TabID == tabId)
                {
                    //Found Parent - so add descendents
                    for (int descendantIndex = index + 1; descendantIndex <= list.Count - 1; descendantIndex++)
                    {
                        TabInfo descendantTab = list[descendantIndex];

                        if ((tabLevel == Null.NullInteger))
                        {
                            tabLevel = parentTab.Level;
                        }

                        if (descendantTab.Level > tabLevel)
                        {
                            //Descendant so add to collection
                            descendantTabs.Add(descendantTab);
                        }
                        else
                        {
                            break; // TODO: might not be correct. Was : Exit For
                        }
                    }
                    break; // TODO: might not be correct. Was : Exit For
                }
            }
            return descendantTabs;
        }


        public void Add(TabInfo tab)
        {
            Add(tab.TabID, tab);
            if (tab.ParentId == Null.NullInteger)
            {
                AddToChildren(tab);
                list.Add(tab);
            }
            else
            {
                for (int index = 0; index <= list.Count - 1; index++)
                {
                    TabInfo parentTab = list[index];
                    if (parentTab.TabID == tab.ParentId)
                    {
                        int childCount = AddToChildren(tab);
                        list.Insert(index + childCount, tab);
                    }
                }
            }
            //Add to localized tabs
            if (tab.PortalID == Null.NullInteger || IsLocalizationEnabled(tab.PortalID))
            {
                AddToLocalizedTabs(tab);
            }
        }
        public void AddRange(IEnumerable<TabInfo> tabs)
        {
            foreach (TabInfo tab in tabs)
            {
                Add(tab);
            }
        }
        public List<TabInfo> AsList()
        {
            return list;
        }
        public List<TabInfo> DescendentsOf(int tabId)
        {
            return GetDescendants(tabId, Null.NullInteger);
        }

        public List<TabInfo> DescendentsOf(int tabId, int originalTabLevel)
        {
            return GetDescendants(tabId, originalTabLevel);
        }

        public ArrayList ToArrayList()
        {
            ArrayList tabs = new ArrayList();
            foreach (TabInfo tab in list)
            {
                tabs.Add(tab);
            }
            return tabs;
        }

        public TabCollection WithCulture(string cultureCode, bool includeNeutral)
        {
            List<TabInfo> tabs = null;
            TabCollection collection = null;
            if (IsLocalizationEnabled())
            {
                if (string.IsNullOrEmpty(cultureCode))
                {
                    //No culture passed in - so return all tabs
                    collection = this;
                }
                else if (!localizedTabs.TryGetValue(cultureCode.ToLowerInvariant(), out tabs))
                {
                    collection = new TabCollection(new List<TabInfo>());
                }
                else
                {
                    if (!includeNeutral)
                    {
                        //Remove neutral culture tabs
                        collection = new TabCollection(from t in tabs
                                                        where t.CultureCode.ToLowerInvariant() == cultureCode.ToLowerInvariant()
                                                        select t);
                    }
                    else
                    {
                        collection = new TabCollection(tabs);
                    }
                }
            }
            else
            {
                //Return all tabs
                collection = this;
            }
            return collection;
        }


        public List<TabInfo> WithParentId(int parentId)
        {
            List<TabInfo> tabs = null;
            if (!children.TryGetValue(parentId, out tabs))
            {
                tabs = new List<TabInfo>();
            }
            return tabs;
        }

        public TabInfo WithTabId(int tabId)
        {
            TabInfo t = null;
            if (ContainsKey(tabId))
            {
                t = this[tabId];
            }
            return t;
        }

        public TabInfo WithTabNameAndParentId(string tabName, int parentId)
        {
            return (from t in list
                    where t.TabName.Equals(tabName, StringComparison.InvariantCultureIgnoreCase)
                    && t.ParentId == parentId
                    select t).SingleOrDefault();
        }

        public TabInfo WithTabName(string tabName)
        {
            return (from t in list
                    where !string.IsNullOrEmpty(t.TabName) && t.TabName.Equals(tabName, StringComparison.InvariantCultureIgnoreCase)
                    select t).FirstOrDefault();
        }

    }
}
